package com.alibaba.citrus.ots.sales.plan.facade.service.salesplan.audit;

import com.alibaba.acm.shaded.com.google.common.collect.Maps;
import com.alibaba.citrus.ots.common.annotation.EpochTransactional;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.sales.plan.annotation.CommonRedisLock;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.SalesPlanWriteService;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.audit.SalesPlanAuditWriteService;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.report.SalesPlanReportQueryService;
import com.alibaba.citrus.ots.sales.plan.api.salesplan.report.SalesPlanReportWriteService;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.DimensionDTO;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.QuerySalesPlanAuditRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.QuerySalesPlanReportRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.SalesPlanAuditTaskQueryRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.SalesPlanBatchAuditRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.SalesPlanBatchAuditResponse;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.SalesPlanReportQueryRequest;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.TaskSubmitBodyDTO;
import com.alibaba.citrus.ots.sales.plan.dto.api.request.TaskSubmitRequest;
import com.alibaba.citrus.ots.sales.plan.functions.salesplan.audit.SalesPlanAuditEntity;
import com.alibaba.citrus.ots.sales.plan.functions.salesplan.report.SalesPlanReportEntity;
import com.alibaba.citrus.ots.sales.plan.model.SalesPlanReportAuditStatusEnum;
import com.alibaba.citrus.ots.sales.plan.model.SalesPlanReportBizTypeEnum;
import com.alibaba.citrus.ots.sales.plan.model.SalesPlanReportStatusEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalePlanAuditStatusEnum;
import com.alibaba.citrus.ots.sales.plan.model.enums.SalesPlanStatusEnum;
import com.alibaba.citrus.ots.sales.plan.repository.MeshAuditFlowRepository;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanAuditRepository;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanAuditTaskRepository;
import com.alibaba.citrus.ots.sales.plan.repository.SalesPlanReportRepository;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanAuditSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanAuditTaskSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanReportSDO;
import com.alibaba.citrus.ots.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.cz.base.tool.page.PageResult;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcots.contants.BcOtsConstants;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.alibaba.citrus.ots.sales.plan.contants.SalesPlanLockKey.BATCH_AUDIT_TASK_PREFIX;

@Service
public class SalesPlanAuditWriteServiceImpl implements SalesPlanAuditWriteService {

    private final Log log = Log.getLogger(SalesPlanAuditWriteServiceImpl.class);

    @Resource
    private SalesPlanReportRepository salesPlanReportRepository;

    @Resource
    private SalesPlanAuditRepository salesPlanAuditRepository;

    @Resource
    private SalesPlanWriteService salesPlanWriteService;

    @Resource
    private SalesPlanReportQueryService salesPlanReportQueryService;

    @Resource
    private MeshAuditFlowRepository meshAuditFlowRepository;

    @Resource
    private SalesPlanAuditTaskRepository salesPlanAuditTaskRepository;

    @Resource
    private SalesPlanReportWriteService salesPlanReportWriteService;

    private final static String SALES_PLAN_REPORT_SWITCH = "TRUE";

    /**
     * 更新审核单状态
     * 通过/通过/驳回/终止等状态  纪元审批流回调
     *
     * @param request
     * @return
     */
    @Override
    @FacadeInvoker
    @EpochTransactional(appCode="bc_ots", dataSourceCode = "cr_ots", dataSourceType = "app")
    public Result<Boolean> updateSalesPlanAuditStatus(SalesPlanAuditSDO request) {
        // 参数校验
        checkSalesPlanAudit(request);

        // 查询审批单
        QuerySalesPlanAuditRequest auditRequest = new QuerySalesPlanAuditRequest();
        auditRequest.setId(request.getId());
        SalesPlanAuditSDO salesPlanAuditSDO = salesPlanAuditRepository.load(auditRequest);
        if (null == salesPlanAuditSDO) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-16-018", request.getId()));
        }

        // 更新审核单状态
        Result<Boolean> updateResult = edit(request);
        if (!updateResult.isSuccess() || !updateResult.getResult()) {
            throw new FacadeException("OTS-02-003-01-16-016");
        }

        // 查询提报单信息
        QuerySalesPlanReportRequest reportRequest = new QuerySalesPlanReportRequest();
        reportRequest.setId(salesPlanAuditSDO.getReportOrderId());
        SalesPlanReportSDO salesPlanReportSDO = salesPlanReportRepository.load(reportRequest);
        if (null == salesPlanReportSDO) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-16-019", salesPlanAuditSDO.getReportOrderId()));
        }

        // 更新提报单状态或者计划状态
        if (SalePlanAuditStatusEnum.FINISHED.getCode().equals(request.getAuditStatus())) {
            // 审批单通过
            // 审批新接口开关，开关打开执行新接口代码
            if (SALES_PLAN_REPORT_SWITCH.equals(BcOtsConstants.SALES_PLAN_REPORT_SWITCH())) {
                auditPass(salesPlanReportSDO, SalesPlanReportAuditStatusEnum.APPROVED.getCode(), SALES_PLAN_REPORT_SWITCH);
            } else {
                auditPass(salesPlanReportSDO, SalesPlanReportAuditStatusEnum.APPROVED.getCode());
            }
        } else {
            // 审批单不通过：提报单状态回滚
            auditFail(salesPlanReportSDO, SalesPlanReportAuditStatusEnum.REVIEW_REJECTED.getCode());
            // 有前序提报单需要重新生成审批单
            if (1 != salesPlanReportSDO.getIsLeafTask()) {
                Result<Boolean> result = salesPlanReportWriteService.reOpen(salesPlanReportSDO);
                log.info("审批驳回处理前序提报单结果：{}", JSONObject.toJSONString(result));
            }
        }
        return updateResult;
    }

    @Override
    @FacadeInvoker
    public Result<String> create(SalesPlanAuditSDO salesPlanAuditSDO) {
        SalesPlanAuditEntity salesPlanAuditEntity = SalesPlanAuditEntity.of(salesPlanAuditSDO);
        String salesPlanAuditId = salesPlanAuditEntity.save();
        return Result.success(salesPlanAuditId);
    }

    @Override
    @FacadeInvoker
    public Result<Boolean> edit(SalesPlanAuditSDO salesPlanAuditSDO) {
        SalesPlanAuditEntity salesPlanAuditEntity = SalesPlanAuditEntity.of(salesPlanAuditSDO);
        Boolean edit = salesPlanAuditEntity.edit();
        return Result.success(edit);
    }

    /**
     * 批量审批任务
     *
     * @param request
     * @return
     */
    @Override
    @FacadeInvoker
    @CommonRedisLock(redisLockPrefix = BATCH_AUDIT_TASK_PREFIX)
    public Result<SalesPlanBatchAuditResponse> batchAuditTask(SalesPlanBatchAuditRequest request) {
        // 参数校验
        checkAuditTask(request);
        SalesPlanBatchAuditResponse response = new SalesPlanBatchAuditResponse(0, 0, Maps.newHashMap());
        Map<String, String> errorInfoMap = response.getErrorInfoMap();
        request.getDimensionDTOList().forEach(dimensionDTO -> {
            // 处理单条任务
            String errorInfo = doSubmitTask(dimensionDTO, request);
            if (StringUtils.isNotBlank(errorInfo)) {
                // 先简单使用维度id识别错误
                errorInfoMap.put(dimensionDTO.getBizId(), errorInfo);
                response.setFailNum(response.getFailNum() + 1);
                log.error("审批发生异常，信息如下：{}", JSONObject.toJSONString(errorInfoMap));
            } else {
                response.setSucNum(response.getSucNum() + 1);
            }
        });

        return Result.success(response);
    }

    private String doSubmitTask(DimensionDTO dimensionDTO, SalesPlanBatchAuditRequest request) {
        String errorInfo = null;
        try {
            // 查询提报单
            Result<SalesPlanReportSDO> reportSDOResult = salesPlanReportQueryService.querySalesPlanReport(convert(dimensionDTO, request));
            if (null == reportSDOResult || null == reportSDOResult.getResult()) {
                return "提报单不存在";
            }
            SalesPlanReportSDO salesPlanReportSDO = reportSDOResult.getResult();
            if (SalesPlanReportStatusEnum.REPORTED.getCode() != salesPlanReportSDO.getStatus()) {
                return "当前状态不能审批";
            }
            // 查询审核单
            List<SalesPlanAuditSDO> salesPlanAuditSDOS = salesPlanAuditRepository.querySalesPlanAuditList(buildAuditRequest(salesPlanReportSDO.getId()));
            if (CollectionUtils.isEmpty(salesPlanAuditSDOS)) {
                return "审核单不存在";
            }
            salesPlanAuditSDOS = salesPlanAuditSDOS.stream().filter(salesPlanAuditSDO -> SalePlanAuditStatusEnum.RUNNING.getCode().equals(salesPlanAuditSDO.getAuditStatus())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(salesPlanAuditSDOS)) {
                return "没有可审批的审批单";
            }
            // 查询审核任务
            String auditOrderId = salesPlanAuditSDOS.get(0).getId();
            PageResult<List<SalesPlanAuditTaskSDO>> listPageResult = salesPlanAuditTaskRepository.pageQuery(buildTaskQueryRequest(auditOrderId));
            if (null == listPageResult || listPageResult.getTotal() < 1) {
                return "审核任务不存在";
            }
            SalesPlanAuditTaskSDO salesPlanAuditTaskSDO = listPageResult.getContent().get(0);
            // 提交任务
            String submitUserTaskErrorInfo = meshAuditFlowRepository.submitUserTask(convertTaskSubmitRequest(salesPlanAuditTaskSDO.getTaskCode(), request));
            if (StringUtils.isNotBlank(submitUserTaskErrorInfo)) {
                return submitUserTaskErrorInfo;
            }
        } catch (Exception e) {
            errorInfo = "处理审批任务发生异常";
            log.error("SalesPlanAuditWriteServiceImpl#batchAuditTask_fail " + errorInfo, e);
        }
        return errorInfo;
    }

    private QuerySalesPlanAuditRequest buildAuditRequest(String reportOrderId) {
        QuerySalesPlanAuditRequest auditRequest = new QuerySalesPlanAuditRequest();
        auditRequest.setReportOrderIdList(Lists.newArrayList(reportOrderId));
        return auditRequest;
    }

    private SalesPlanAuditTaskQueryRequest buildTaskQueryRequest(String auditOrderId) {
        SalesPlanAuditTaskQueryRequest taskQueryRequest = new SalesPlanAuditTaskQueryRequest();
        taskQueryRequest.setAuditOrderId(auditOrderId);
        taskQueryRequest.setStart(0);
        taskQueryRequest.setLimit(1);
        return taskQueryRequest;
    }

    private TaskSubmitRequest convertTaskSubmitRequest(String taskId, SalesPlanBatchAuditRequest auditRequest) {
        TaskSubmitRequest request = new TaskSubmitRequest();
        request.setTaskId(taskId);
        TaskSubmitBodyDTO bodyDTO = new TaskSubmitBodyDTO();
        bodyDTO.setAction(auditRequest.getAction());
        bodyDTO.setComment(auditRequest.getComment());
        bodyDTO.setParameters(null);
        request.setBody(bodyDTO);
        request.setOperatorId(auditRequest.getOperatorId());
        return request;
    }

    private SalesPlanReportQueryRequest convert(DimensionDTO dimensionDTO, SalesPlanBatchAuditRequest request) {
        SalesPlanReportQueryRequest reportQueryRequest = new SalesPlanReportQueryRequest();
        reportQueryRequest.setBizId(dimensionDTO.getBizId());
        reportQueryRequest.setBizType(dimensionDTO.getBizType());
        reportQueryRequest.setModelId(request.getModelId());
        reportQueryRequest.setModelType(request.getModelType());
        return reportQueryRequest;
    }

    private void checkAuditTask(SalesPlanBatchAuditRequest request) {
        if (null == request) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-15-004"));
        }
        if (CollectionUtils.isEmpty(request.getDimensionDTOList())) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-15-005"));
        }
        if (null == request.getModelId()) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-15-006"));
        }
        if (null == request.getModelType()) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-15-007"));
        }
    }

    /**
     * 审批通过
     * @param request
     * @param auditStatus
     */
    private void auditPass(SalesPlanReportSDO request, Integer auditStatus) {
        // 如果是最后一级别提报单终审通过, 计划推进至审核完成
        if (SalesPlanReportBizTypeEnum.BUSINESS_DIMENSION_REPORT.getCode().equals(request.getBizType())) {
            SalesPlanSDO salesPlanSDO = new SalesPlanSDO();
            salesPlanSDO.setId(Long.parseLong(request.getPlanId()));
            salesPlanSDO.setStatus(SalesPlanStatusEnum.TO_BE_SYNC.getCode());
            Result<Integer> updateResult = salesPlanWriteService.updateSalesPlanStatus(salesPlanSDO);
            if (!updateResult.isSuccess() || updateResult.getResult() < 1) {
                throw new FacadeException("OTS-02-003-01-16-017");
            }
        }
        // 更新提报单状态
        updateSalesPlanReportStatus(request.getId(), SalesPlanReportStatusEnum.FINISH.getCode(), auditStatus);
    }

    /**
     * 重写审批通过
     * @param request
     * @param auditStatus
     */
    private void auditPass(SalesPlanReportSDO request, Integer auditStatus, String str) {
        // 最后一级没有提报单，月度计划推进至审核完成
        if (StringUtils.isBlank(request.getParentId())) {
            SalesPlanSDO salesPlanSDO = new SalesPlanSDO();
            salesPlanSDO.setId(Long.parseLong(request.getPlanId()));
            salesPlanSDO.setStatus(SalesPlanStatusEnum.TO_BE_SYNC.getCode());
            Result<Integer> updateResult = salesPlanWriteService.updateSalesPlanStatus(salesPlanSDO);
            if (!updateResult.isSuccess() || updateResult.getResult() < 1) {
                throw new FacadeException("OTS-02-003-01-16-017");
            }
        }
        // 更新提报单状态
        updateSalesPlanReportStatus(request.getId(), SalesPlanReportStatusEnum.FINISH.getCode(), auditStatus);
    }

    /**
     * 审批不通过
     * 包括审批终止，审批驳回，审批撤回
     * @param request
     * @param auditStatus
     */
    private void auditFail(SalesPlanReportSDO request, Integer auditStatus) {
        // 审批不通过，回滚提报单状态
        updateSalesPlanReportStatus(request.getId(), SalesPlanReportStatusEnum.TO_REPORT.getCode(), auditStatus);
    }

    /**
     * 参数校验
     * @param request
     */
    private void checkSalesPlanAudit(SalesPlanAuditSDO request) {
        if (null == request) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-15-015","传入参数为空"));
        }

        if (null == request.getId()) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-15-015","传入审核单据id不能为空"));
        }
    }

    private void updateSalesPlanReportStatus(String id , Integer status, Integer auditStatus) {
        SalesPlanReportSDO salesPlanReportSDO = new SalesPlanReportSDO();
        salesPlanReportSDO.setId(id);
        salesPlanReportSDO.setStatus(status);
        salesPlanReportSDO.setAuditStatus(auditStatus);
        salesPlanReportSDO.setGmtModified(new Date());
        SalesPlanReportEntity salesPlanReportEntity = SalesPlanReportEntity.of(salesPlanReportSDO);
        Boolean edit = salesPlanReportEntity.edit();
        if (!edit) {
            throw new FacadeException(ErrorMessage.code("OTS-02-003-01-16-003"));
        }
    }
}
